


/**
 * 运行的类 负责整个项目的子进程运行操作
 */

import { spawn, exec } from 'child_process';
import { ipcMain } from 'electron';
import { appendFile, writeFileSync, existsSync, mkdirSync } from 'fs';
import * as path from 'path';
import iconvLite from 'iconv-lite';


class childProcess {

    #Processbank = {};//储存进程的对象的
    #mainWindow = null;

    constructor(mainWindow) {
        this.#mainWindow = mainWindow;//主窗口
    }

    /**
     * 创建一个新的进程
     * @param {String} key 进程key
     * @param {String} execute 命令
     * @param {String} cwd 运行目录
     */
    createProcess(key, execute, cwd, coding = 'UTF8') {
        let execStr = execute;
        let parameter = [];//参数
        if (Array.isArray(execute)) {
            execStr = execute[0];//命令
            parameter = execute.slice(1);
        }

        if (execStr == '') return Promise.resolve(false);//没有配置命令
        if (!existsSync(cwd)) return Promise.resolve(false);//不存在的运行目录
        if (this.#Processbank[key]) return Promise.resolve(false);//已经在运行了


        return new Promise((resolve) => {
            let ls = spawn(execStr, parameter, { cwd, encoding: 'buffer' });

            setTimeout(() => {
                if (ls.exitCode != null) {
                    // 启动失败
                    resolve(false);
                    return;
                }
                this.#Processbank[key] = ls;//存入全局缓存
                let logPath = path.join(cwd, 'logs', 'consoleLog.log');
                if (/^frp\-.*$/.test(key)) {
                    // frp的日志
                    logPath = path.join(cwd, 'logs', key, 'consoleLog.log');
                }

                let pathDir = path.parse(logPath);
                if (!existsSync(pathDir.dir)) {
                    // 目录不在的话
                    mkdirSync(pathDir.dir, { recursive: true });//创建目录
                }
                writeFileSync(logPath, '');//清空上次的日志

                ls.stdout.on('data', (data) => {
                    let strData = iconvLite.decode(data, coding).replace(/[\r\n]+/g, '\r\n');
                    appendFile(logPath, strData, { flag: 'a' }, err => { });
                    this.#mainWindow.webContents.send('console_data', key, strData);//通知渲染进程
                });

                ls.stderr.on('data', (data) => {
                    let strData = iconvLite.decode(data, coding).replace(/[\r\n]+/g, '\r\n');
                    appendFile(logPath, strData, { flag: 'a' }, err => { });
                    this.#mainWindow.webContents.send('console_data', key, strData);//通知渲染进程
                });

                ls.on('close', (code) => {
                    this.#mainWindow.webContents.send('console_close', key);//通知渲染进程
                    if (this.#Processbank[key]) exec("taskkill /f /pid " + this.#Processbank[key].pid)//结束子进程
                    delete this.#Processbank[key];//如果关闭了 就冲缓存中删除
                });
                resolve(true);
            }, 0);
        });
    }

    /**
     * 判断指定key进程是否在运行
     * @param {String} key 进程key
     */
    isRunProcess(key) {
        if (!this.#Processbank[key]) return false;//已经没运行了
        if (this.#Processbank[key].exitCode != null) {
            delete this.#Processbank[key];//如果关闭了 就冲缓存中删除
            return false;//进程已经退出了
        }
        return true;
    }


    /**
     * 向指定key进程发送信息（写入）
     * @param {String} key 进程key
     * @param {String} str 信息
     */
    writeProcess(key, str, coding) {
        if (!this.#Processbank[key]) return false;//已经没运行了
        try {
            this.#Processbank[key].stdin.write(iconvLite.encode(str, coding));//发送信息 
        } catch (error) {
            return false;
        }
        return true;
    }

    /**
     * 关闭指定key的进程
     * @param {String} key 进程key
     */
    closeProcess(key) {
        if (!this.#Processbank[key]) return true;//已经没运行了
        try {
            exec("taskkill /f /pid " + this.#Processbank[key].pid)//结束子进程
            delete this.#Processbank[key];//如果关闭了 就冲缓存中删除
            this.#mainWindow.webContents.send('console_close', key);//通知渲染进程
        } catch (error) {
            return false;
        }
        return true;
    }

}




export default function (mainWindow) {
    let classObj = new childProcess(mainWindow);
    // 调用创建进程
    ipcMain.handle('createProcess', async (e, key, execute, cwd, coding = 'UTF8') => {
        return await classObj.createProcess(key, execute, cwd, coding);
    });

    // 调用关闭进程
    ipcMain.handle('closeProcess', (e, key) => {
        return classObj.closeProcess(key);
    });

    // 调用检查进程是否在运行
    ipcMain.handle('isRunProcess', (e, key) => {
        return classObj.isRunProcess(key);
    });

    // 向进程发送信息
    ipcMain.handle('writeProcess', (e, key, str, coding) => {
        if (!coding) coding = 'UTF8';
        return classObj.writeProcess(key, str, coding);
    });

    return classObj;
}